package org.java.reflection;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description 反射的基本使用
 * @Date 2024/8/13 10:12
 * @Created by 10574
 */
@Slf4j
public class ReflectionDemo {
//    private static final Logger log = LoggerFactory.getLogger(ReflectionDemo.class);

    public static void main(String[] args) {
        //1. 获取Class对象测试
        getClassObject();
        //2. 通过反射创建对象测试
        createObjectByReflection();
        //3 .通过反射获取构造方法
        getConstructorsByReflection();
        //4 .通过反射获取成员变量
        getFieldsByReflection();
        //5. 通过反射获取方法
        getMethodByReflection();
        //6. 通过Method类调用方法
//        callMethodByReflection();
        //7. 对比正射和反射
//          compareOrthoAndReflection();
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    private static class Student {
        private String name;
        private Integer age;
        public String address;
        public static final String PUBLIC_CONSTANT = "123";
        protected static final String PROTECT_CONSTANT = "234";

        public Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        private Student(String name) {
            this.name = name;
        }
    }

    /**
     * 获取Class对象:
     * 1. 使用Class.forName()
     * 2. 使用类名.class
     * 3. 使用实例对象的getClass()方法
     */
    private static void getClassObject() {
        try {
            //1
            Class<?> studentClass1 = Class.forName("org.java.reflection.ReflectionDemo$Student");
            //2
            Class<Student> studentClass2 = Student.class;
            //3
            Class<? extends Student> studentClass3 = new Student("zhanyurui", 23).getClass();
            log.info("studentClass1:{}", studentClass1.getName());
            log.info("studentClass2:{}", studentClass2.getName());
            log.info("studentClass3:{}", studentClass3.getName());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过反射创建对象:
     * 1. 通过Class对象的newInstance()方法
     * 2. 通过Constructor的newInstance()方法。
     */
    private static void createObjectByReflection() {
        try {
            // 1
            Student student1 = Student.class.newInstance();
            Constructor<Student> constructor = Student.class.getConstructor(String.class, Integer.class);
            // 2
            Student student2 = constructor.newInstance("good", 24);
            log.info(student1.toString());
            log.info(student2.toString());

        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
                 InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 反射获取类的构造器:
     * 1. Class的getConstructors()，获取所有public的构造方法
     * 2. Class的getDeclaredConstructors(), 获取所有的构造方法
     * 3. Class的getConstructor(Class[] parameterTypes),返回指定参数类型public的构造器
     * 4. Class的getDeclaredConstructor(Class[] parameterTypes), 返回指定参数类型的public和private的构造方法
     */
    private static void getConstructorsByReflection() {
        log.info("--------------------getConstructors()--------------------");
        final AtomicInteger i = new AtomicInteger(1);
        Arrays.stream(Student.class.getConstructors()).forEach(constructor -> {
            log.info("构造方法{}; 修饰符:{}; 参数: ", i.getAndIncrement(), getModifierStr(constructor.getModifiers()));
            Arrays.stream(constructor.getParameters()).forEach(parameter -> {
                log.info(parameter.getName() + ":" + parameter.getType().getName() + ";");
            });
        });
        log.info("--------------------getConstructors()--------------------");

        i.set(1);
        log.info("--------------------getDeclaredConstructors()--------------------");
        Arrays.stream(Student.class.getDeclaredConstructors()).forEach(constructor -> {
            log.info("构造方法{}; 修饰符:{}; 参数: ", i.getAndIncrement(), getModifierStr(constructor.getModifiers()));
            Arrays.stream(constructor.getParameters()).forEach(parameter -> {
                log.info(parameter.getName() + ":" + parameter.getType() + ";");
            });
        });
        log.info("--------------------getDeclaredConstructors()--------------------");

        i.set(1);
        log.info("--------------------getConstructor(Class[] parameterTypes)--------------------");
        try {
            final Constructor<Student> constructor = Student.class.getConstructor(String.class, Integer.class);
            log.info("构造方法{}; 修饰符:{}; 参数: ", i.getAndIncrement(), getModifierStr(constructor.getModifiers()));
            Arrays.stream(constructor.getParameters()).forEach(parameter -> {
                log.info(parameter.getName() + ":" + parameter.getType() + ";");
            });
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        log.info("--------------------getConstructor(Class[] parameterTypes)--------------------");

        i.set(1);
        log.info("--------------------getDeclaredConstructor(Class[] parameterTypes)--------------------");
        try {
            final Constructor<Student> constructor = Student.class.getDeclaredConstructor(String.class);
            log.info("构造方法{}; 修饰符:{}; 参数: ", i.getAndIncrement(), getModifierStr(constructor.getModifiers()));
            Arrays.stream(constructor.getParameters()).forEach(parameter -> {
                log.info(parameter.getName() + ":" + parameter.getType() + ";");
            });
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        log.info("--------------------getDeclaredConstructor(Class[] parameterTypes)--------------------");
    }

    /**
     * Tips: 成员变量包括: 实例成员变量 静态成员变量 常量
     * 1. Class的getFields()，获取所有public的成员变量
     * 2. Class的getDeclaredFields(), 获取所有(public private)的的成员变量
     * 3. Class的getField(String name),返回指定参数类型public的成员变量
     * 4. Class的getDeclaredField(String name), 返回指定参数类型的public和private的成员变量
     */
    private static void getFieldsByReflection() {
        log.info("--------------------getFields()--------------------");
        Arrays.stream(Student.class.getFields()).forEach(field -> {
            log.info("修饰符:{}, 类型:{}, 变量名:{}", getModifierStr(field.getModifiers()), field.getType().getTypeName(), field.getName());
        });
        log.info("--------------------getFields()--------------------");

        log.info("--------------------getDeclaredFields()--------------------");
        Arrays.stream(Student.class.getDeclaredFields()).forEach(field -> {
            log.info("修饰符:{}, 类型:{}, 变量名:{}", getModifierStr(field.getModifiers()), field.getType().getTypeName(), field.getName());
        });
        log.info("--------------------getDeclaredFields()--------------------");


        log.info("--------------------getField(String name)--------------------");
        try {
            Field field1 = Student.class.getField("address");
            log.info("修饰符:{}, 类型:{}, 变量名:{}", getModifierStr(field1.getModifiers()), field1.getType().getTypeName(), field1.getName());
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        log.info("--------------------getField(String name)--------------------");


        log.info("--------------------getDeclaredField(String name)--------------------");
        try {
            Field field2 = Student.class.getDeclaredField("name");
            log.info("修饰符:{}, 类型:{}, 变量名:{}", getModifierStr(field2.getModifiers()), field2.getType().getTypeName(), field2.getName());
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        log.info("--------------------getDeclaredField(String name)--------------------");
    }

    /**
     * 1. Class的getMethods(), 获取类的public类型的方法
     * 2. Class的getDeclaredMethods(), 获取类的所有方法
     * 3. Class的getMethod(String name, Class[] parameterTypes), 获取类的特定方法,只包括public
     * 4. Class的getDeclaredMethod(String name, Class[] parameterTypes), 获取类的特定方法
     */
    private static void getMethodByReflection() {
        log.info("--------------------getMethods()--------------------");
        Arrays.stream(ReflectionDemo.class.getMethods()).forEach(method -> {
            log.info("修饰符:{}, 返回值类型:{}, 方法名:{}", getModifierStr(method.getModifiers()), method.getReturnType().getName(), method.getName());
        });
        log.info("--------------------getMethods()--------------------");

        log.info("--------------------getDeclaredMethods()--------------------");
        Arrays.stream(ReflectionDemo.class.getDeclaredMethods()).forEach(method -> {
            log.info("修饰符:{}, 返回值类型:{}, 方法名:{}", getModifierStr(method.getModifiers()), method.getReturnType().getTypeName(), method.getName());
        });
        log.info("--------------------getDeclaredMethods()--------------------");

        log.info("--------------------getMethod(String name, Class[] parameterTypes)--------------------");
        try {
            Method method1 = ReflectionDemo.class.getMethod("getModifierStr", int.class);
            log.info("修饰符:{}, 返回值类型:{}, 方法名:{}", getModifierStr(method1.getModifiers()), method1.getReturnType().getTypeName(), method1.getName());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        log.info("--------------------getMethod(String name, Class[] parameterTypes)--------------------");

        log.info("--------------------getDeclaredMethod(String name, Class[] parameterTypes)--------------------");
        try {
            Method method2 = ReflectionDemo.class.getDeclaredMethod("getMethodByReflection");
            log.info("修饰符:{}, 返回值类型:{}, 方法名:{}", getModifierStr(method2.getModifiers()), method2.getReturnType().getTypeName(), method2.getName());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        log.info("--------------------getDeclaredMethod(String name, Class[] parameterTypes)--------------------");
    }

    /**
     * 通过Method.invoke反射调用方法，debug查看调用链
     */
    private static void callMethodByReflection() {
        try {

            Method method = Class.forName("org.java.reflection.ReflectionDemo").getDeclaredMethod("target", String.class);
            method.setAccessible(true);
            method.invoke(null, "123");
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException |
                 ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 打印method.invoke方法的调用栈
     *
     * @param str 随机字符串
     */
    private static void target(String str) {
        new Exception("#" + str).printStackTrace();
        System.out.println("invoke target method");
    }

    /**
     * 对比正射和反射
     */
    private static void compareOrthoAndReflection() {
        // 正射
        Student student1 = new Student("zhanyurui", 24);
        log.info(student1.toString());
        //反射
        try {
            Student student2 = (Student) Class.forName("org.java.reflection.ReflectionDemo$Student").getConstructor(String.class, Integer.class).newInstance("zhanyurui1", 25);
            log.info(student2.toString());
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException |
                 ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

    }

    public static String getModifierStr(int modifier) {
        if (Modifier.isPublic(modifier)) {
            return "public";
        }
        if (Modifier.isProtected(modifier)) {
            return "protect";
        }
        if (Modifier.isPrivate(modifier)) {
            return "private";
        }
        return null;
    }
}
